import { type } from 'os';

(function () {
	// 类型别名如果声明了泛型坑位，那其实就等价于一个接受参数的函数：
	type Factory<T> = T | number | string;

	//伪代码
	function Factory(typeArg: any) {
		return [typeArg, 'number', 'string'];
	}

	//Stringify 会将一个对象类型的所有属性类型置为 string
	type Stringify<T> = {
		[k in keyof T]: string;
	};

	//Clone 则会进行类型的完全复制
	type Clone<T> = {
		[K in keyof T]: T[K];
	};

	/*工具类型 Partial 会将传入的对象类型复制一份，但会额外添加一个?,现在我们获得了一个属性均为可选的山寨版：*/
	type Partial<T> = {
		[P in keyof T]?: T[P];
	};

	interface IFoo {
		prop1: string;
		prop2: string;
		prop3: boolean;
		prop4: () => void;
	}

	type PartialFoo = Partial<IFoo>;
	// 等价于
	interface PartialFoo1 {
		prop1?: string;
		prop2?: string;
		prop3?: boolean;
		prop4?: () => void;
	}
	// 或者
	type PartialFoo2 = {
		prop1?: string;
		prop2?: string;
		prop3?: boolean;
		prop4?: () => void;
	};

	//# 条件类型
	type isEqual<T> = T extends true ? 1 : 2;

	type A = isEqual<true>; //1

	type B = isEqual<false>; // 2

	type C = isEqual<'lys'>; //2

	// 通常泛型会被作为条件类型中的判断条件（T extends Condition，或者 Type extends T）以及返回值（即 : 两端的值），这也是我们筛选类型需要依赖的能力之一。

	//#泛型约束与默认值

	//泛型同样有着默认值的设定
	type Factory1<T = boolean> = T | number | string;

	const foo: Factory1 = false;

	//泛型约束
	//在函数中，我们只能在逻辑中处理：
	function add(source: number, add: number) {
		if (typeof source !== 'number' || typeof add !== 'number') {
			throw new Error('Invalid arguments!');
		}

		return source + add;
	}

	// 而在泛型中，我们可以使用 extends 关键字来约束传入的泛型参数必须符合要求。
	type ResStatus<ResCode extends number> = ResCode extends 10000 | 10001 | 10002 ? 'success' : 'failure';

	type Res1 = ResStatus<10000>; // "success"
	type Res2 = ResStatus<20000>; // "failure"

	//type Res3 = ResStatus<'10000'>; // 类型“string”不满足约束“number”。

	//想让这个类型别名可以无需显式传入泛型参数也能调用，并且默认情况下是成功地，这样就可以为这个泛型参数声明一个默认值
	type ResStatus1<ResCode extends number = 10000> = ResCode extends 10000 | 10001 | 10002 ? 'success' : 'failure';
	//在 TypeScript 中，泛型参数存在默认约束（在下面的函数泛型、Class 泛型中也是）。这个默认约束值在 TS 3.9 版本以前是 any，而在 3.9 版本以后则为 unknown。在 TypeScript ESLint 中，你可以使用 no-unnecessary-type-constraint 规则，来避免代码中声明了与默认约束相同的泛型约束。

	//#多泛型关联
	//我们不仅可以同时传入多个泛型参数，还可以让这几个泛型参数之间也存在联系
	type Conditional<Type, Condition, TruthyResult, FalsyResult> = Type extends Condition ? TruthyResult : FalsyResult;

	//  "passed!"
	type Result1 = Conditional<'lys', string, 'passed!', 'rejected!'>;

	// "rejected!"
	type Result2 = Conditional<'lys', boolean, 'passed!', 'rejected'>;

	//多个泛型参数之间的依赖，其实指的即是在后续泛型参数中，使用前面的泛型参数作为约束或默认值
	type ProcessInput<Input, SecondInput extends Input = Input, ThirdInput extends Input = Input> = number;
})();
